package org.haifi.game.compiler;

import java.util.Map;

import javax.annotation.PostConstruct;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.haifi.game.mina.GameParamParser;
import org.haifi.game.reflection.GameReflect;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

/**
 * 动态生成及编译GamePamamParse实现类
 * 
 * TODO:可以考虑为每个method动态生成专用的实现类，这样可以避免掉if判断。但现在不知道这样做是否能提高效率
 * 
 * 我Ｘ，老子服了，在web容器中，就是跳不出aspectj的错误
 * 
 * @author joycube2
 * 
 */
@Component
@Lazy(false)
@DependsOn("gameReflect")
public class GameParamParserFactory {
	public GameParamParserFactory() {
		log.info("GameParamParserFactory init");
	}

	@SuppressWarnings("unchecked")
	@PostConstruct
	public GameParamParser generateGameParamParse() {
		if (gameParamParser != null) {
			log.info("use generated object instance");
			return gameParamParser;
		}
		log.info("genrating gameParamParser.");
		// 生成代码
		StringBuilder sb = new StringBuilder();
		sb.append("package org.haifi.game.mina;");

		sb.append("import org.apache.commons.logging.Log;");
		sb.append("import org.apache.commons.logging.LogFactory;");
		sb.append("import org.haifi.game.mina.GameParamParser;");
		sb.append("import com.google.protobuf.MessageLite;");

		sb.append("import org.haifi.game.pb.TestAction.*;");

		Map<Short, Class> paramCmdIdMap = GameReflect.getParamCmdIds();
		for (Short cmdId : paramCmdIdMap.keySet()) {
			Class clazz = paramCmdIdMap.get(cmdId);
			if (cmdId == 0) {
				continue;
			}
			sb.append("import org.haifi.game.pb."
					+ clazz.getSimpleName().replaceAll("Param$", "") + ".*;");
		}

		sb
				.append("public class GameParamParseImpl1 implements GameParamParser {");

		sb.append("	public GameParamParseImpl1() {");
		sb.append("		log.info(\"应该初始化这里\");");
		sb.append("	}");

		sb.append("	 ");
		sb.append("	public MessageLite parseParam(short cmdId, byte[] protoData) {");
		sb.append("		MessageLite obj = null;");
		sb.append("		try {");
		sb.append("			if (cmdId == 0) {");
		sb.append("				obj = TestActionParam.parseFrom(protoData);");
		sb.append("			}");

		for (Short cmdId : paramCmdIdMap.keySet()) {
			Class clazz = paramCmdIdMap.get(cmdId);
			if (cmdId == 0) {
				continue;
			}
			sb.append("else if(cmdId == " + cmdId + ") {");
			sb.append("		obj = " + clazz.getSimpleName()
					+ ".parseFrom(protoData);");
			sb.append("}");
		}

		sb.append("			else {");
		sb.append("				log.error(\"uncategoried cmdId:\" + cmdId);");
		sb.append("			}");
		sb.append("		} catch (Exception e) {");
		sb.append("			log.error(\"ERROR\", e);");
		sb.append("			}");
		sb.append("			return obj;");
		sb.append("		}");

		Map<Class, Short> returnCmdIdMap = GameReflect.getReturnCmdIds();

		sb.append("  ");
		sb
				.append(" public MessageLite parseMessage(short cmdId, byte[] protoData) {");
		sb.append("	MessageLite obj = null;");
		sb.append("	try {");
		sb.append("		if (cmdId == 0) {");
		sb.append("			obj = TestActionTestMessage.parseFrom(protoData);");
		sb.append("		}");

		for (Class clazz : returnCmdIdMap.keySet()) {
			Short cmdId = returnCmdIdMap.get(clazz);
			if (cmdId == 0) {
				continue;
			}
			String classSimpleName = clazz.getName().replace("$Builder", "");
			classSimpleName = classSimpleName.substring(classSimpleName
					.indexOf("$") + 1);
			sb.append("else if(cmdId == " + cmdId + ") {");
			sb.append("		obj = " + classSimpleName + ".parseFrom(protoData);");
			sb.append("}");
		}

		sb.append("		else {");
		sb.append("			log.error(\"uncategoried cmdId:\" + cmdId);");
		sb.append("		}");
		sb.append("	} catch (Exception e) {");
		sb.append("		log.error(\"ERROR\", e);");
		sb.append("	}");
		sb.append("	return obj;");
		sb.append("}");

		sb
				.append("		private static final Log log = LogFactory.getLog(GameParamParseImpl1.class);");
		sb.append("}");

		String code = sb.toString();
		log.info(code);
		String name = "org.haifi.game.mina.GameParamParseImpl1";

		gameParamParser = (GameParamParser) JavaCompilerUtil.compiler(name,
				code);
		return gameParamParser;
	}

	private GameParamParser gameParamParser;

	private static final Log log = LogFactory
			.getLog(GameParamParserFactory.class);
}
